//not runnable, got some issues
package SMUVE;

import java.net.*;
import java.io.*;
import SMUVE.*;
import static SMUVE.Debug.debug;
//import SMUVE.SMUVE_Server.Server_Thread;

public class DataManager {

	String hostname;
	int client_port;
	int update_port;
	String filename;
	ObjectList<Room> rooms = new ObjectList<Room>();
	ObjectList<Player> players = new ObjectList<Player>();
	ObjectList<Item> items= new ObjectList<Item>();
	static final String delimiter = SMUVE.Msg_Pipe.delimiter;

	public DataManager(String hostname, int client_port, int update_port) {
		this.hostname = hostname;
		this.client_port = client_port;
		this.update_port = update_port;
		filename = "SMUVE_" + hostname + "_" + client_port + "_" + update_port + ".conf";
	}
		
	
	/* Room methods */
	public boolean add_room(Room room) {
		boolean retval = false;
		if (!room_exists(room.get_name())) {
			debug("Adding room: " + room);
			retval = rooms.add(room);
		}

		return(retval);
	}

	public boolean remove_room(Room room)
	{
		debug("Removing Room: " + room);
		return rooms.remove(room);
	}

	public Room[] get_rooms() {
		return(rooms.toArray(new Room[0]));
	}

	public boolean add_player(Player player) {
		boolean retval = false;
		if (!player_exists(player.get_name())) {
			debug("Adding player: " + player);
			retval = players.add(player);
		}

		return(retval);
	}
	// possible change from one string to two strings

	public boolean portal_exists(String room, String to_room) {
		boolean retval = false;

		Room r1 = get_room(room);

		return(r1.get_portal(to_room) != null);
	}

	public boolean add_portal(String room, Portal portal, boolean add_local) {
		boolean retval = true;

		/* Don't allow rooms of the same name to be connected */
		Room r = get_room(room);
		if(r==null)
			return false;
		if (!r.portal_exists(portal)) {
			if (room.equals(portal.get_room()))
				return(false);

			if (room_exists(room)) {
				Room r1 = get_room(room);
					
				if (!add_local) {
					retval = false;
					/* if the room to connect to is local go ahead and add it */
					if (portal.get_server().equals(hostname) &&
							portal.get_client_port() == client_port &&
							portal.get_update_port() == update_port) {
						debug("adding local portal");
						Room r2 = get_room(portal.get_room());
						retval = r2.add_portal(new Portal(room, hostname,
							client_port, update_port));
					} else {
						debug("adding remote portal");
						try {
							String server = "localhost";
							//if (!portal.get_server().equals(hostname))
								server = portal.get_server();
							Socket sock = new Socket(server,
								portal.get_client_port());
							Msg_Pipe pipe = new Msg_Pipe(sock);
							try {
								Thread.sleep(100); /* XXX: let the pipe get set up */
							}
							catch (InterruptedException e) {
								// do nothing
							}
							if (!pipe.login("server", "server_pass")) {
								debug("server login failed");
								return(false);
							}
							retval = pipe.add_portal(portal.get_room(), room,
								hostname, client_port, update_port, true);

							debug("remote add_portal returned: " + retval);
							
							pipe.close();
							sock.close();
						}
						catch (UnknownHostException e) {
							debug("unknown host: " + portal.get_server());
							return(false);
						}
						catch (IOException e) {
							debug("IOException");
							return(false);
						}
					}

				}
				if (retval) { /* to room has been successfully added */
					/* don't allow a portal to a room with the same name as
					 * a portal that already exists.  Remote or local.
					 */
					if (r1.get_portal(portal.get_room()) == null)
						retval = retval && r1.add_portal(portal);
					else
						retval = false;
				}

				debug("add_portal returned" + retval);
			}
			else
				debug("tried to add portal to non-existent room: " + room);
		}

		return(retval);
	}

	public boolean remove_portal(Room room, String to_room)
	{
		boolean retval=false;
		Portal p1=room.get_portal(to_room);
		if(p1==null)
			return false;
		room.remove_portal(p1);
		if(p1.get_server().equals(hostname)&&p1.get_client_port() == 
			client_port && p1.get_update_port() == update_port)
		{
			Room r=get_room(to_room);
			if(r==null)
				return false;
			Portal p2=r.get_portal(room.get_name());
			if(p2==null)
				return false;
			r.remove_portal(p2);
			retval=true;
		}
		else
		{
			try {
				String server = p1.get_server();
				Socket sock = new Socket(server,
					p1.get_client_port());
				Msg_Pipe pipe = new Msg_Pipe(sock);
				try {
					Thread.sleep(1000); /* XXX: let the pipe get set up */
				}
				catch (InterruptedException e) {
					// do nothing
				}
				//que?
				if (!pipe.login("server", "server_pass")) {
					debug("server login failed");
					return(false);
				}
				retval = pipe.remove_portal(p1.get_room(), room.get_name());

				debug("remote add_portal returned: " + retval);
				
				pipe.close();
				sock.close();
			}
			catch (UnknownHostException e) {
				debug("unknown host: " + p1.get_server());
				return(false);
			}
			catch (IOException e) {
				debug("IOException");
				return(false);
			}
		}
		return true;
	}
	// Roddy
	public boolean add_item(Item item){
		boolean retval = false;
		if (!item_exists(item.get_name())) {
			debug("Adding Item: " + item.get_name());
			retval = items.add(item);
		}
	
		return(retval);
	}

	public boolean remove_item(Item item)
	{
		debug("Removing Item: " + item.get_name());
		return items.remove(item);
	}

	//Roddy 
	public boolean remove_player(Player player)
	{
		debug("Removing Player: " + player);
		return players.remove(player);
	}
	
	public String get_current_room(String player) {
		String retval = "";
		Player p = get_player(player);
		if (p != null) {
			retval = p.get_room();
		}

		return(retval);
	}

	public Item[] get_player_items(String player) {
		ObjectList<Item> itemList=new ObjectList<Item>();
		Player p = get_player(player);
		for(int i=0; i<items.size(); i++)
		{
			if(items.get(i).get_location().equals(player))
				itemList.add(items.get(i));
		}

		return(itemList.toArray(new Item[0]));
	}


	public boolean move(String player, String room) {
		int i;
		boolean retval = false;

		/* XXX: needs to check that the move is valid */
		for (i = 0; i < players.size(); i++) {
			Player p = players.get(i);
			if (p.get_name().equals(player)) {
				p.set_room(room);
				retval = true;
				break;
			}
		}

		return(retval);
	}

	

	public boolean room_exists(String room) {
		boolean retval = false;

		for (int i = 0; i < rooms.size(); i++) {
			if (rooms.get(i).get_name().equals(room)) {
				retval = true;
				break;
			}
		}

		return(retval);
	}

	// Roddy
	public boolean player_exists(String player)
	{
		boolean retval = false;

		for (int i = 0; i < players.size(); i++) {
			if (players.get(i).get_name().equals(player)) {
				retval = true;
				break;
			}
		}

		return(retval);
	}
	
	//Roddy
	public boolean item_exists(String item)
	{
		boolean retval = false;

		for (int i = 0; i < items.size(); i++) {
			if (items.get(i).get_name().equals(item)) {
				retval = true;
				break;
			}
		}

		return(retval);
	}
	
	
/*
	 public boolean portal_exists(Room r1, Room r2)
	 {
		 Portal p=r1.get_portal(r2.get_name());
		 if(p==null)
			 return false;
		 return true;
	 }
*/
	
	 public Room get_room(String room) {
			Room r = null;

			for (int i = 0; i < rooms.size(); i++) {
				if (rooms.get(i).get_name().equals(room)) {
					r = rooms.get(i);
					break;
				}
			}

			return(r);
		}
	 
	public Player get_player(String name) {
		Player p = null;

		debug("get_player: name = '" + name + "'");
		for (int i = 0; i < players.size(); i++) {
			if (players.get(i).get_name().equals(name)) {
				p = players.get(i);
				break;
			}
		}

		return(p);
	}
	
	public Item get_item(String name) {
		Item item = null;

		debug("get_item: name = '" + name + "'");
		for (int i = 0; i < items.size(); i++) {
			if (items.get(i).get_name().equals(name)) {
				item = items.get(i);
				break;
			}
		}

		return(item);
	}
	//roddy
	public Item[] get_items() {
		return(items.toArray(new Item[0]));
	}
	
	public boolean lock_item(Item i)
	{
		i.lock();
		return true;
	}
	
	public boolean unlock_item(Item i)
	{
		i.unlock();
		return true;
	}

	public Player[] get_players() {
		return(players.toArray(new Player[0]));
	}
	
	public Player[] get_room_players(String room)
	{
		ObjectList<Player> playerList=new ObjectList<Player>();
		for(int i=0; i< players.size(); i++)
		{
			if(players.get(i).get_room().equals(room) && players.get(i).get_active())
				playerList.add(players.get(i));
		}
		return playerList.toArray(new Player[0]);
	}

	public Item[] get_room_items(String room)
	{
		ObjectList<Item> itemList=new ObjectList<Item>();
		for(int i=0; i< items.size(); i++)
		{
			if(items.get(i).get_location().equals(room))
				itemList.add(items.get(i));
		}
		return(itemList.toArray(new Item[0]));
	}

	public boolean modify_room(Room room, String newName, String newDescription)
	{
		String oldName=room.get_name();
		room.set_name(newName);
		room.set_description(newDescription);
		debug("before for loop");
		for(int i=0; i<players.size(); i++)
		{
			debug("in for loop");
			debug(players.get(i).get_name());
			debug(players.get(i).get_room());
			debug(room.get_name());
			if(players.get(i).get_room().equals(oldName))
			{
				debug("changing a player");
				players.get(i).set_room(newName);
			}
		}
		for(int i=0; i<items.size(); i++)
		{
			if(items.get(i).get_location().equals(oldName))
			{
				items.get(i).set_location(newName);
			}
		}
		for(int i=0; i<rooms.size(); i++)
		{
			Room r =rooms.get(i);
			Portal p=r.get_portal(oldName);
			if(p!=null)
			{
				r.remove_portal(p);
				r.add_portal(new Portal(newName, hostname, client_port, update_port));
			}
		}
		return true;
	}

	public boolean modify_player(Player player, String newName)
	{
		player.set_name(newName);
		return true;
	}

	public boolean modify_item(Item item, String newName, String newDescription)
	{
		item.set_name(newName);
		item.set_description(newDescription);
		return true;
	}

	public boolean pick_up_item(String player, String item) {
		boolean retval = false;
		Item i = get_item(item);
		if (i != null) {
			retval = i.pick_up(player);
		}

		return(retval);
	}

	public boolean put_down_item(String player, String item) {
		boolean retval = false;
		Item i = get_item(item);
		Player p = get_player(player);
		if (i != null && p != null) {
			retval = i.put_down(p.get_room());
		}

		return(retval);
	}
	
	public boolean put_down_item(Player player, Item item) {
		boolean retval = false;
		Item i = item;
		Player p = player;
		if (i != null && p != null) {
			retval = i.put_down(p.get_room());
		}

		return(retval);
	}

	public boolean save_state() {
		boolean retval = false;
		try {
			FileWriter fstream = new FileWriter(filename);
			BufferedWriter out = new BufferedWriter(fstream);

			/* Add players to datafile */
			for (int i = 0; i < players.size(); i++) {
				Player p = players.get(i);
				out.write("player" + delimiter + p.get_name() + delimiter +
					p.get_room() + delimiter + p.get_password() + "\n");
				debug("added player " + p.get_name());
			}

			/* Add rooms to datafile */
			for (int i = 0; i < rooms.size(); i++) {
				Room r = rooms.get(i);
				out.write("room" + delimiter + r.get_name() + delimiter +
					r.get_description() + "\n");
				debug("added room " + r.get_name());
			}

			/* Add portals to datafile */
			for (int i = 0; i < rooms.size(); i++) {
				Room r = rooms.get(i);
				String[] portals = r.get_portals();
				if (portals != null) {
					for (int j = 0; j < portals.length; j++) {
						debug("adding portal " + portals[j]);
						Portal p = r.get_portal(portals[j]);
						if (p != null) {
							out.write("portal" + delimiter + r.get_name() + delimiter +
								p.get_room() + delimiter + p.get_server() + delimiter + 
								p.get_client_port() + delimiter + p.get_update_port() + "\n");
							debug("added portal " + p.get_room());
						}
					}
				}
			}

			/* Add items to datafile */
			for (int i = 0; i < items.size(); i++) {
				Item item = items.get(i);
				out.write("item" + delimiter + item.get_name() + delimiter +
					item.get_location() + delimiter + item.get_description() +
					delimiter + item.get_in_room() + "\n");
				debug("added item " + item.get_name());
			}

			out.close();
			retval = true;
		}
		catch (Exception e) {
			debug("Exception");
			e.printStackTrace();
		}

		return(retval);
	}

	public String get_type(String str) {
		String[] result = parse_line(str);
		String retval = "";
		if (result.length > 0)
			retval = result[0];

		return(retval);
	}

	public String[] parse_line(String str) {
		String[] result = str.split("\\" + delimiter);

		return(result);
	}

	public boolean load_state() {
		boolean retval = false;
		debug("print reading state file");
		
		File temp1 = new File("Clue_board.txt");
		boolean t1 = temp1.exists();
		
		File temp2 = new File("Monopoly.txt");		
		boolean t2 = temp2.exists();

		File temp3 = new File("Battleship.txt");
		boolean t3 = temp3.exists();

		File file = new File(filename);
		boolean success = file.exists();

		if(!success){
			InputStream tempIn;  
			OutputStream out;
			File use = null;
			
		    boolean copy = false;
			if(t1){
				use = temp1;
				copy = true;
			}
			else if(t2){
				use = temp2;
				copy = true;
			}
			else if(t3){
				use = temp3;
				copy = true;
			}
	
			if(copy){
					try{
						out = new FileOutputStream(file);
						tempIn = new FileInputStream(use);
						// Transfer bytes from in to out
						byte[] buf = new byte[1024];
						int len;
						while ((len = tempIn.read(buf)) > 0) {
							out.write(buf, 0, len);
						}
						tempIn.close();
						out.close();
					} catch (Exception e){
					}
					success = true;
			}
		}
		
		if(success){
			try {
				FileReader fstream = new FileReader(filename);
				BufferedReader in = new BufferedReader(fstream);
	
				String line;
				while ((line = in.readLine()) != null) {
					String type = Msg_Pipe.get_message_type(line);
					String body = Msg_Pipe.get_message_body(line);
					String[] result = Msg_Pipe.parse_message(body);
					debug("got type: " + type);
					if (type.equals("room")) {
						if (result.length == 2) {
							String room = result[0];
							String description = result[1];
							debug("read in room " + room);
							add_room(new Room(room, description));
						}
					}
					else if (type.equals("player")) {
						if (result.length == 3) {
							String name = result[0];
							String room = result[1];
							String password = result[2];
							debug("read in player " + name);
							add_player(new Player(name, room, password));
						}
					}
					else if (type.equals("portal")) {
						if (result.length == 5) {
							String room = result[0];
							String to_room = result[1];
							String server = result[2];
							if(server.equals("localhost"))
									server = hostname;
							int cport = Integer.parseInt(result[3]);
							int uport = Integer.parseInt(result[4]);
							debug("read in portal from " + room + " to " + to_room);
							add_portal(room, new Portal(to_room, server, cport, uport), false);
						}
					}
					else if (type.equals("item")) {
						if (result.length == 4) {
							String name = result[0];
							String location = result[1];
							String desc = result[2];
							boolean in_room = Boolean.parseBoolean(result[3]);
							debug("read in item " + name);
							add_item(new Item(name, location, desc, in_room));
						}
					} 
					else
						debug("got unknown entry in state file: " + line);
				}
			}
			catch (Exception e) {
				debug("Exception");
				e.printStackTrace();
				debug("After stack 1");
				
			}
	
			return(retval);
		}
		else {
			//Load Admin user, server user, and home room
			debug("Adding stuff");
			add_room(new Room("Den", "Home Sweet Home"));
			add_player(new Player("server", "omnipresent", "server_pass"));
			add_player(new Player("admin", "omnipresent", "admin_pass"));
			add_item(new Item("Pen", "Den", "Sharp writing utensil", true));
			return(retval);
		}
	}
}
